package com.igoal.web.security;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.httpclient.auth.InvalidCredentialsException;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.Authentication;
import org.springframework.security.AuthenticationException;
import org.springframework.security.AuthenticationManager;
import org.springframework.security.AuthenticationServiceException;
import org.springframework.security.BadCredentialsException;
import org.springframework.security.GrantedAuthority;
import org.springframework.security.GrantedAuthorityImpl;
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
import org.springframework.security.providers.encoding.PasswordEncoder;
import org.springframework.security.userdetails.UserDetails;
import org.springframework.security.userdetails.UsernameNotFoundException;
import org.springframework.transaction.annotation.Transactional;

import com.igoal.dao.UserDAOExt;
import com.igoal.entity.Role;
import com.igoal.entity.User;
import com.igoal.service.UserManagerExt;

public class CustomAuthenticationManager implements AuthenticationManager {

	@Qualifier("userDaoExt")
	private UserDAOExt userDetailsService;
	private PasswordEncoder passwordEncoder;
	private UserManagerExt userManagerExt;

	@Autowired
	public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
		this.passwordEncoder = passwordEncoder;
	}

	@Autowired
	public void setUserManagerExt(UserManagerExt userManagerExt) {
		this.userManagerExt = userManagerExt;
	}

	@Autowired
	public void setUserDetailsService(UserDAOExt userDetailsService) {
		this.userDetailsService = userDetailsService;
	}
	
	@Transactional(readOnly=true)
	public Authentication authenticate(Authentication authentication)
			throws AuthenticationException {

		if (StringUtils.isBlank((String) authentication.getPrincipal())
				|| StringUtils.isBlank((String) authentication.getCredentials())) {
			throw new BadCredentialsException("Invalid username/password");
		}

		User user = null;

		GrantedAuthority[] grantedAuthorities = null;

		try {
			String username = (String) authentication.getPrincipal();
			UserDetails userDetails = userDetailsService.loadUserByUsername(username);
			user = (User) userDetails;
			String credential = (String) authentication.getCredentials();
			if (!user.getPassword().equals(passwordEncoder.encodePassword(credential, null))
					|| userManagerExt.isDisable(username)) {
				throw new InvalidCredentialsException();
			}
		} catch (InvalidCredentialsException e) {
			throw new BadCredentialsException(e.getMessage());
		} catch (UsernameNotFoundException ex) {
			throw ex;
		} catch (Exception e) {
			throw new AuthenticationServiceException(
					"Currently we are unable to process your request. Kindly try again later.");
		}

		List<Role> roles = new ArrayList<Role>(user.getRoles());
		grantedAuthorities = new GrantedAuthority[roles.size()];

		for (int i = 0; i < roles.size(); i++) {
			Role role = roles.get(i);
			GrantedAuthority authority = new GrantedAuthorityImpl(role.getName());
			grantedAuthorities[i] = authority;
		}

		return new UsernamePasswordAuthenticationToken(user, authentication.getCredentials(),
				grantedAuthorities);
	}

}
